#include "SQLiteGenreDAO.h"

SQLiteGenreDAO::SQLiteGenreDAO(sqlite3 *database) {
	this->database = database;
}

void SQLiteGenreDAO::save(const Genre& genre) {
	sqlite3_stmt* statement;
	const char* sql = "insert into genre values (?,?)";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_null(statement, 1);
	sqlite3_bind_text(statement, 2, genre.getName().c_str(), -1, SQLITE_STATIC);

	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		std::ostringstream oss;
		oss << "Cannot save the genre. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

void SQLiteGenreDAO::update(const Genre& genre) {
	sqlite3_stmt* statement;
	const char* sql = "update genre set name=? where id=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_text(statement, 1, genre.getName().c_str(), -1, SQLITE_STATIC);
	sqlite3_bind_int(statement, 2, genre.getId());

	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		std::ostringstream oss;
		oss << "Cannot update the genre. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

void SQLiteGenreDAO::remove(const Genre& genre) {
	sqlite3_stmt* statement;
	const char* sql = "delete from genre where id=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_int(statement, 1, genre.getId());

	rc = sqlite3_step(statement);
	sqlite3_finalize(statement);
	if (rc != SQLITE_DONE) {
		std::ostringstream oss;
		oss << "Cannot remove the genre. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}
}

Genre SQLiteGenreDAO::loadGenreById(int id) {
	sqlite3_stmt* statement;
	const char* sql = "select * from genre where id=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "(loadGenreById): Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_int(statement, 1, id);

	rc = sqlite3_step(statement);
	if (rc != SQLITE_ROW) {
		if (rc == SQLITE_DONE)
			return Genre();
		std::ostringstream oss;
		oss << "Cannot load the genre. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	Genre genre(sqlite3_column_int(statement, 0),
			(const char*) sqlite3_column_text(statement, 1));
	sqlite3_finalize(statement);

	return genre;
}

Genre SQLiteGenreDAO::loadGenreByName(const std::string& name) {
	sqlite3_stmt* statement;
	const char* sql = "select * from genre where name=?";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	sqlite3_bind_text(statement, 1, name.c_str(), -1, SQLITE_STATIC);

	rc = sqlite3_step(statement);
	if (rc != SQLITE_ROW) {
		if (rc == SQLITE_DONE)
			return Genre();
		std::ostringstream oss;
		oss << "Cannot load the genre. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	Genre genre(sqlite3_column_int(statement, 0),
			(const char*) sqlite3_column_text(statement, 1));
	sqlite3_finalize(statement);

	return genre;
}

int SQLiteGenreDAO::countAll() {
	sqlite3_stmt* statement;
	const char* sql = "select count(id) from genre";

	int rc = sqlite3_prepare_v2(database, sql, -1, &statement, NULL);
	if (rc != SQLITE_OK) {
		std::ostringstream oss;
		oss << "Error on prepare statement. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	rc = sqlite3_step(statement);
	if (rc != SQLITE_ROW) {
		std::ostringstream oss;
		oss << "Cannot count genres. SQLite code: " << rc;
		throw SQLiteException(oss.str());
	}

	int count = sqlite3_column_int(statement, 0);
	sqlite3_finalize(statement);

	return count;
}

